package org.lex.game.sudoku.view.cell;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

import ms.sudoku.util.IntSet;

import common.Sudokus;

public class LabelCellView extends JComponent implements CellView {

	private static final long serialVersionUID = -6691328483707987984L;

	public static void main(String[] args) throws Exception {
		UIManager.put("swing.boldMetal", Boolean.FALSE);
		UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
		GridLayout layout = new GridLayout(3, 3, 0, 0);
		JPanel contentPane = new JPanel(layout);
		contentPane.setBorder(new CompoundBorder(new EmptyBorder(5, 5, 6, 6), new LineBorder(Color.BLACK, 2)));

		Font f = new Font(Font.DIALOG, Font.BOLD, 30);
		Border b = new LineBorder(Color.BLACK, 1);
		for (int i = 0; i < 9; i++) {
			LabelCellView cell = new LabelCellView(i, i);
			cell.setFont(f);
			cell.setBorder(b);
			contentPane.add(cell);
		}

		JFrame frame = new JFrame("Cell");
		frame.setSize(300, 300);
		frame.setContentPane(contentPane);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}

	private static final Font NORMAL_FONT = new Font(Font.DIALOG, Font.BOLD, 30);
	private static final Font HINT_FONT = new Font(Font.DIALOG, Font.PLAIN, 16);

	private CellResource renderer = CellResource.getDefault();

	private final int column;
	private final int row;

	private String text = "";

	private boolean ignoreRepaint = false;

	/**
	 * Create the panel.
	 */
	public LabelCellView(int row, int column) {
		this.column = column;
		this.row = row;
		this.initialize();
	}

	public int getColumn() {
		return column;
	}

	public int getRow() {
		return row;
	}

	@Override
	public void set(int number, IntSet hints, boolean error, boolean editable, boolean selected) {
		ignoreRepaint = true;
		Color fg = this.renderer.getFallbackForeground();
		Color bg = this.renderer.getFallbackBackground();
		if (error) {
			// error
			fg = this.renderer.getErrorForeground();
			bg = this.renderer.getErrorBackground();
		} else {
			// not error
			if (selected) {
				// not error & selected
				fg = this.renderer.getSelectedForeground();
				bg = this.renderer.getSelectedBackground();
			} else {
				if (editable) {
					// not error & not selected & editable
					fg = this.renderer.getEditableForeground();
					bg = this.renderer.getEditableBackground();
				} else {
					// not error & not selected & not editable
					fg = this.renderer.getNormalForeground();
					bg = this.renderer.getNormalBackground();
				}
			}
		}
		String text = "";
		Font font = NORMAL_FONT;
		if (Sudokus.notEmpty(number)) {
			font = NORMAL_FONT;
			text = Integer.toString(number);
		}
		if (null != hints && false == hints.isEmpty()) {
			font = HINT_FONT;
			StringBuilder buf = new StringBuilder(hints.size() * 2);
			int charCount = 0;
			for (int h : hints) {
				charCount++;
				buf.append(h);
				if (charCount % 3 == 0) {
					buf.append("\n");
				}
			}
			text = buf.toString();
		}

		this.setFont(font);
		this.setText(text);
		this.setBackground(bg);
		this.setForeground(fg);
		this.ignoreRepaint = false;
		this.repaint();
	}

	private void setText(String text) {
		this.text = text;
	}

	@Override
	protected void paintComponent(Graphics g) {
		if (ignoreRepaint) {
			return;
		}
		Insets insets = this.getInsets();
		int x = insets.left;
		int y = insets.top;
		int width = this.getWidth() - insets.left - insets.right;
		int height = this.getHeight() - insets.top - insets.bottom;
		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

		g2.translate(x, y);
		// background
		g2.setColor(this.getBackground());
		g2.fillRect(0, 0, width, height);
		// foreground
		Font f = this.getFont();
		g2.setColor(this.getForeground());
		g2.setFont(f);

		Rectangle2D textBounds = this.getFontMetrics(f).getStringBounds(text, g2);
		int textX = (int) Math.round((width - textBounds.getWidth()) / 2.0 - textBounds.getX());
		int textY = (int) Math.round((height - textBounds.getHeight()) / 2.0 - textBounds.getY());
		g2.drawString(text, textX, textY);
		// clean
		g2.translate(-x, -y);
	}

	private void initialize() {
		this.setFocusable(true);
		this.setOpaque(true);
	}
}
